package com.chen.serviceorder.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.chen.internalcommon.constant.CommonStatusEnum;
import com.chen.internalcommon.constant.OrderConstants;
import com.chen.internalcommon.dto.OrderInfo;
import com.chen.internalcommon.dto.PriceRule;
import com.chen.internalcommon.dto.ResponseResult;
import com.chen.internalcommon.request.OrderRequest;
import com.chen.internalcommon.request.PriceRuleIsNewRequest;
import com.chen.internalcommon.response.OrderDriverResponse;
import com.chen.internalcommon.response.TerminalAroundSearchResponse;
import com.chen.internalcommon.util.RedisPrefixUtils;
import com.chen.serviceorder.mapper.OrderInfoMapper;
import com.chen.serviceorder.remote.ServiceDriverUserClient;
import com.chen.serviceorder.remote.ServiceMapClient;
import com.chen.serviceorder.remote.ServicePriceClient;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author chenLiuPing
 **/
@Service
@Slf4j
public class OrderService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ServiceMapClient serviceMapClient;

    @Autowired
    private ServiceDriverUserClient serviceDriverUserClient;

    @Autowired
    private ServicePriceClient servicePriceClient;
    public String test() {
        return orderInfoMapper.selectList(null).toString();

    }
    // TODO 添加事务？
    public ResponseResult add(OrderRequest orderRequest) {
        log.info("创建订单===");
        // 校验当前城市是否有可用司机
        String cityCode = orderRequest.getAddress();
        ResponseResult<Boolean> availableDriverResponse = serviceDriverUserClient.isAvailableDriver(cityCode);
        if (!availableDriverResponse.getData()) {
            log.info("创建订单失败，当前城市：{}没有可用司机", cityCode);
            return ResponseResult.fail(CommonStatusEnum.CITY_DRIVER_EMPTY);
        }

        Long passengerId = orderRequest.getPassengerId();
        // 校验该乘客是否有正在进行的订单
        if (orderGoingOn(passengerId)) {
            log.info("乘客：{}创建订单失败，存在正在进行的订单", passengerId);
            return ResponseResult.fail(CommonStatusEnum.ORDER_GOING_ON);
        }
        // 检验计价规则是否最新
        PriceRuleIsNewRequest priceRuleIsNewRequest = new PriceRuleIsNewRequest(orderRequest.getFareType(), orderRequest.getFareVersion());
        ResponseResult isNewResponse = servicePriceClient.isNew(priceRuleIsNewRequest);
        if (isNewResponse.getCode() != 1) {
            log.info("计价规则不存在 订单添加失败");
            return isNewResponse;
        } else {
            boolean isNew = (boolean) isNewResponse.getData();
            if (!isNew) {
                log.info("计价规则不是最新 订单添加失败");
                return ResponseResult.fail(CommonStatusEnum.PRICE_RULE_CHANGED);
            }
        }
      //   校验下单的城市和计价规则是否正常
        if (!isPriceRuleExists(orderRequest.getFareType())) {
            log.info("当前城市不提供叫车服务,订单创建失败");
            return ResponseResult.fail(CommonStatusEnum.CITY_SERVICE_NOT_SERVICE);
        }
        // 校验设备是否属于黑名单
        String deviceCode = orderRequest.getDeviceCode();
        if (isBlackDevice(deviceCode)) {
            log.info("设备{}订单次数过多，创建订单失败", deviceCode);
            return ResponseResult.fail(CommonStatusEnum.DEVICE_IS_BLACK);
        }
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderRequest, orderInfo);
        LocalDateTime now = LocalDateTime.now();
        orderInfo.setGmtCreate(now);
        orderInfo.setGmtModified(now);
        orderInfo.setOrderStatus(OrderConstants.ORDER_START);
        orderInfoMapper.insert(orderInfo);
        dispatchRealTimeOrder(orderInfo);

        return ResponseResult.success();
    }


    /**
     * 实时订单派单逻辑
     * @param orderInfo 订单
     */
    public  void dispatchRealTimeOrder(OrderInfo orderInfo) {
        // 获取乘客位置
        String depLatitude = orderInfo.getDepLatitude();
        String depLongitude = orderInfo.getDepLongitude();
        String center = depLatitude + "," + depLongitude;
        // 分别2km 4km 5km 范围进行搜索可用车辆
        List<Integer> radiusList = Arrays.asList(2000, 4000, 5000);

        for (Integer radius : radiusList) {
            ResponseResult<List<TerminalAroundSearchResponse>> searchResponse = serviceMapClient.aroundSearch(center, radius);
            if (searchResponse.getData() == null) {
                log.info("实时订单派单失败：{}", searchResponse.getMessage());
                continue;
            }
            // 遍历searchResponse 获取可用车辆
            List<TerminalAroundSearchResponse> terminalAroundSearchResponseList =  searchResponse.getData();
            log.info("搜索附件{}m可用车辆，查询到{}辆车可用", radius, terminalAroundSearchResponseList.size());
            // 判断查询到的车辆是否可用 进行订单派送
            for (TerminalAroundSearchResponse terminalAroundSearchResponse : terminalAroundSearchResponseList) {
                Long carId = terminalAroundSearchResponse.getCarId();
                String latitude = terminalAroundSearchResponse.getLatitude();
                String longitude = terminalAroundSearchResponse.getLongitude();
                OrderDriverResponse orderDriverResponse = serviceDriverUserClient.getAvailableDriver(carId).getData();
                if (orderDriverResponse != null) {
                    Long driverId = orderDriverResponse.getDriverId();
                    log.info("乘客：{}匹配到了可用司机：{}", orderInfo.getPassengerId(), driverId);

                    // 判断车辆的车型是否符合订单的需求
                    String vehicleType = orderDriverResponse.getVehicleType();
                    if (Objects.equals(vehicleType, orderInfo.getVehicleType())) {
                        String lockKey = (driverId + "").intern();
                        RLock lock = redissonClient.getLock(lockKey);
                        lock.lock();
                            // 判断司机是否有正在进行的订单
                        if (!isDriverOrderGoingOn(driverId)) {
                            // 设置订单中司机车辆的相关信息
                            orderInfo.setDriverAndCarInfo(orderDriverResponse);
                            // 设置位置
                            orderInfo.setReceiveOrderCarLatitude(latitude);
                            orderInfo.setReceiveOrderCarLongitude(longitude);
                            // 设置订单时间和状态
                            orderInfo.setOrderTime(LocalDateTime.now());
                            orderInfo.setOrderStatus(OrderConstants.DRIVER_RECEIVE_ORDER);
                            orderInfoMapper.updateById(orderInfo);
                            lock.unlock();
                        } else {
                            lock.unlock();
                        }
                    }

                }
            }
        }
    }

    /**
     * 根据乘客id判断是否有正在进行的订单
     * @param passengerId 乘客id
     * @return
     */
    private boolean orderGoingOn(Long passengerId) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        List<Integer> orderGoingOn = OrderConstants.getPassengerOrderGoingOn();
        // 查询passengerId的乘客此时的订单状态是在正在进行
        queryWrapper.eq(OrderInfo::getPassengerId, passengerId)
                .and(wrapper -> {
                    wrapper.in(OrderInfo::getOrderStatus, orderGoingOn);
                });
        return orderInfoMapper.selectOne(queryWrapper) != null;
    }

    /**
     * 判断司机是否有正在进行的订单
     */
    private boolean isDriverOrderGoingOn(Long driverId) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        List<Integer> orderGoingOn = OrderConstants.getDriverOrderGoingOn();
        // 查询driverId的司机此时的订单状态是正在进行
        queryWrapper.eq(OrderInfo::getDriverId, driverId)
                .and(wrapper -> {
                    wrapper.in(OrderInfo::getOrderStatus, orderGoingOn);
                });
        return orderInfoMapper.selectCount(queryWrapper) > 0;

    }

    /**
     * 判断设备是否是黑名单中的设备
     */
    private boolean isBlackDevice(String deviceCode) {
        String deviceCodeKey = RedisPrefixUtils.generateDeviceCodeKey(deviceCode);
        String value = stringRedisTemplate.opsForValue().get(deviceCodeKey);
        if (value != null) {
            int integer = Integer.parseInt(value);
            if (integer >= 2) {
                return true;
            }
            stringRedisTemplate.opsForValue().increment(deviceCode);
            return false;
        }
        stringRedisTemplate.opsForValue().set(deviceCodeKey, String.valueOf(1), 1, TimeUnit.HOURS);
        return false;
    }

    /**
     * 查询下单的城市计价规则是否正常
     */
    private boolean isPriceRuleExists(String fareType) {
        String[] split = fareType.split("\\$");
        if (split.length != 2) {
            return false;
        }
        String cityCode = split[0];
        String vehicleType = split[1];
        log.info("cityCode:{}, vehicleType:{}", cityCode, vehicleType);
        PriceRule priceRule = new PriceRule();
        priceRule.setCityCode(cityCode);
        priceRule.setVehicleType(vehicleType);
        ResponseResult<Boolean> responseResult = servicePriceClient.ifExists(priceRule);
        return responseResult.getData();
    }
}
